package me.zhengjie.utils.http;

import me.zhengjie.exception.CommonUtilException;
import org.apache.http.*;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.client.protocol.*;
import org.apache.http.config.Registry;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.RequestExpectContinue;
import org.apache.http.protocol.*;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.SocketTimeoutException;
import java.net.URLEncoder;
import java.util.*;

public class HttpUtils {

	private static final Logger logger = LoggerFactory.getLogger(HttpUtils.class);

	private final static RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(30000)
			.setConnectTimeout(15000).setConnectionRequestTimeout(10000).build();// 设置请求和传输超时时间

	private static PoolingHttpClientConnectionManager defaultPhccm = new PoolingHttpClientConnectionManager();

	protected static PoolingHttpClientConnectionManager getPhccm() {
		return getPhccm(null);
	}

	protected static PoolingHttpClientConnectionManager getPhccm(Registry<ConnectionSocketFactory> socketFactoryRegistry) {
		if (socketFactoryRegistry == null) {
			return defaultPhccm;
		} else {
			PoolingHttpClientConnectionManager p = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
			return p;
		}
	}

	/**
	 * HTTP GET
	 * @param url
	 * @return
	 */
	public static String get(String url) {
		return get(url,null,null, 0);
	}

	/**
	 * HTTP GET
	 * @param url
	 * @return
	 */
	public static String get(String url, Registry<ConnectionSocketFactory> socketFactoryRegistry) {
		return get(url,null,null, 0, socketFactoryRegistry);
	}



	public static String get(String url, int socketTimeout) {
		return get(url, null, null, socketTimeout);
	}
	
	/**
	 * HTTP GET
	 * @param url
	 * @return
	 */
	public static String getWithParamMap(String url, Map<String, String> paramMap) {
		return getWithParamMap(url,paramMap,null);
	}

	/**
	 * HTTP GET
	 * @param url
	 * @return
	 */
	public static String getWithParamMap(String url, Map<String, String> paramMap, String charset) {
		if (charset == null || charset.trim().isEmpty()) {
			charset = "UTF-8";
		}

		try {
			return get(url + "?" + concatParamsWithURLEncode(paramMap, charset),null, charset, 0);
		} catch (UnsupportedEncodingException e) {
			logger.warn("get请求异常(Enocde Param异常)",e);
			throw new CommonUtilException("get请求异常(Enocde Param异常), url: " + url, e);
		}
	}

	
	public static String get(String url, Map<String, String> headers, String charset) {
		return get(url, headers, charset, 0);
	}

	/**
	 * HTTP GET请求
	 * @param url
	 * @return
	 */
	public static String get(String url, Map<String, String> headers, String charset, int socketTimeout) {
		return get(url, headers, charset, socketTimeout, null);
	}


	/**
	 * HTTP GET请求
	 * @return
	 */
	public static String get(String url, Map<String, String> headers, String charset, int socketTimeout,
							 Registry<ConnectionSocketFactory> socketFactoryRegistry) {
		if(charset == null || charset.trim().isEmpty()) {
			charset = "UTF-8";
		}

		CloseableHttpResponse response = null;
		HttpEntity entity = null;

		PoolingHttpClientConnectionManager phccm = getPhccm(socketFactoryRegistry);
		phccm.setMaxTotal(800);// 连接池最大并发连接数
		phccm.setDefaultMaxPerRoute(400);// 单路由最大并发数

		CloseableHttpClient httpclient = null;
		
		if(socketTimeout == 0){
			httpclient = HttpClients.custom().setDefaultRequestConfig(requestConfig)
					.setConnectionManager(phccm).setRetryHandler(new DefaultHttpRequestRetryHandler()).setHttpProcessor(getProcessor()).build();
		}else{
			RequestConfig reqConfig = RequestConfig.custom().setSocketTimeout(socketTimeout)
					.setConnectTimeout(10000).setConnectionRequestTimeout(10000).build();
			httpclient = HttpClients.custom().setDefaultRequestConfig(reqConfig)
					.setConnectionManager(phccm).setRetryHandler(new DefaultHttpRequestRetryHandler()).setHttpProcessor(getProcessor()).build();
		}
		
		HttpGet httpGet = new HttpGet(url);

		// 设置HTTP头信息
		if(headers != null && !headers.isEmpty()) {
			for(Map.Entry<String, String> entry : headers.entrySet()) {
				Header header = new BasicHeader(entry.getKey(), entry.getValue());
				httpGet.addHeader(header);
			}
		} else {
			Header header = new BasicHeader("User-Agent",
					"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.134 Safari/537.36");
			httpGet.addHeader(header);
		}

		try {
			response = httpclient.execute(httpGet);
			entity = response.getEntity();
			if(entity == null){
				return "";
			}
			return EntityUtils.toString(entity,charset);
		} catch(ClientProtocolException e) {
			logger.warn("get请求异常",e);
			throw new CommonUtilException("get请求异常, url: " + url + "headers: " + headers, e);
		} catch(ParseException e) {
			logger.warn("get请求异常",e);
			throw new CommonUtilException("get请求异常, url: " + url + "headers: " + headers, e);
		} catch(IOException e) {
			logger.warn("get请求异常",e);
			throw new CommonUtilException("get请求异常, url: " + url + "headers: " + headers, e);
		} finally {
			if(entity != null) {
				try {
					EntityUtils.consume(entity);
				} catch(IOException e) {
					logger.warn("",e);
				}
			}

			if(response != null) {
				try {
					response.close();
				} catch(IOException e) {
					logger.warn("",e);
				}
			}

			httpGet.releaseConnection();
		}
	}


	/**
	 * HTTP GET请求
	 * @param url
	 * @return
	 */
	public static String getWithRetry(String url) {
		return getWithRetry(url, null, null, 0, null);
	}


	public static String getWithRetry(String url, Map<String, String> headers, String charset, int socketTimeout,
									  Registry<ConnectionSocketFactory> socketFactoryRegistry) {
		int retryCount = 0;
		do{
			try {
				return get(url, headers, charset, socketTimeout, socketFactoryRegistry);
			}catch (Exception e){
				retryCount++;
			}

		}while ( retryCount < 3);

		throw new CommonUtilException("get请求异常, url: " + url + "headers: " + headers);
	}

	/**
	 * 将cookies拼接成请求头中的值
	 *
	 * @param cookiesMap
	 * @return
	 */
	public static String contactCookies(Map<String, String> cookiesMap) {
		if (cookiesMap == null) return null;

		StringBuilder cookiesResult = new StringBuilder();
		Set<Map.Entry<String, String>> entrySet = cookiesMap.entrySet();
		for (Map.Entry<String, String> entry : entrySet) {
			cookiesResult.append(entry.getKey())
					.append("=")
					.append(entry.getValue())
					.append(";");
		}
		if (cookiesResult.length() > 0) {
			cookiesResult.delete(cookiesResult.length() - 1, cookiesResult.length());
		}

		return cookiesResult.toString();
	}

	/**
	 * 取出header中的cookie
	 * @param headers
	 */
	public static Map<String, String> getCookieFromHeader(Header[] headers) {
		if (headers == null || headers.length <= 0) return null;

		Map<String, String> result = new HashMap<>(headers.length);
		String val = null;
		String[] cookieContentArray = null;
		String[] cookieKeyVal = null;
		for (Header getheader : headers) {//导出返回header

			if (!"Set-Cookie".equals(getheader.getName())) {
//				response.addHeader(getheader.getName(), getheader.getValue());
			} else { //存放cookie的头
				val = getheader.getValue();

				if (val != null && val.trim().length() > 0) {
					cookieContentArray = val.split(";");
					if (cookieContentArray != null && cookieContentArray.length > 0
							&& cookieContentArray[0] != null) {

						cookieKeyVal = cookieContentArray[0].split("=");
						if (cookieKeyVal != null && cookieKeyVal.length > 1) {
							result.put(cookieKeyVal[0], cookieKeyVal[1]);
						}
					}
				}
			}
		}

		return result;
	}

	/**
	 * HTTP POST 请求
	 * @param url
	 * @param formData
	 * @return
	 */
	public static String post(String url, Map<String, String> formData) {
		return post(url,null,formData,null, 0);
	}

	/**
	 * HTTP POST 请求
	 * @param url
	 * @param formData
	 * @return
	 */
	public static String post(String url, Map<String, String> formData, int socketTime) {
		return post(url,null,formData,null, socketTime);
	}

	/**
	 * HTTP POST 请求
	 * @param url
	 * @param reqBodyStr
	 * @return
	 */
	public static String post(String url, String reqBodyStr) {
		return post(url,null, reqBodyStr,null);
	}

	/**
	 * HTTP POST 请求
	 * @param url
	 * @param reqBodyStr
	 * @param socketFactoryRegistry
	 * @return
	 */
	public static String post(String url, String reqBodyStr, Registry<ConnectionSocketFactory> socketFactoryRegistry) {
		return post(url,null, reqBodyStr,
				null, "application/json", 0, socketFactoryRegistry);
	}

	/**
	 * HTTP POST请求
	 * @param url
	 * @param reqBodyStr
	 * @param socketFactoryRegistry
	 * @param maybeRedirect 是否有重定向
	 * @return
	 */
	public static String post(String url, String reqBodyStr,
							  Registry<ConnectionSocketFactory> socketFactoryRegistry,
							  boolean maybeRedirect) {
		if (maybeRedirect) {

			return postForRedirect(url, null, reqBodyStr, null, "application/json", 0, socketFactoryRegistry);
		}
		return post(url, null, reqBodyStr, null, "application/json", 0, socketFactoryRegistry);
	}

	/**
	 * HTTP POST请求， 指定超时时间
	 * @param url
	 * @param reqBodyStr
	 * @param socketTimeout
	 * @return
	 */
	public static String post(String url, String reqBodyStr, int socketTimeout) {
		return post(url,null,reqBodyStr,null, socketTimeout);
	}

	/**
	 * HTTP POST 请求
	 * @param url
	 * @param reqBodyStr
	 * @return
	 */
	public static String post(String url, String reqBodyStr, String contentType) {
		return post(url,null,reqBodyStr,null, contentType, 0);
	}

	public static String postRetryWhenConnectTimeout(String url, String reqBodyStr, String contentType, int socketTimeout, int connectTimeout){

		String response = "";
		try{
			response = post(url, null, reqBodyStr, null, contentType, socketTimeout, connectTimeout, null);
		}catch (RuntimeException e){
			if(e.getCause() instanceof ConnectTimeoutException){
				response = post(url, null, reqBodyStr, null, contentType, socketTimeout, connectTimeout, null);
			}
		}
		return response;
	}

	/**
	 * HTTP POST 请求
	 * @param url
	 * @param reqBodyStr
	 * @param contentType
	 * @param maybeRedirect 是否有重定向
	 * @return
	 */
	public static String post(String url, String reqBodyStr, String contentType, boolean maybeRedirect) {
		if (maybeRedirect) {

			return postForRedirect(url, null, reqBodyStr, null, contentType, 0, null);
		}
		return post(url, reqBodyStr, contentType);
	}

	public static String post(String url, Map<String, String> headers, Map<String, String> formData, String charset) {
		return post(url, headers, formData, charset, null, 0);
	}

	public static String post(String url, Map<String, String> headers, Map<String, String> formData, String charset, int socketTime) {
		return post(url, headers, formData, charset, null, socketTime);
	}

	public static String post(String url, Map<String, String> headers, Map<String, String> formData, String charset, Registry<ConnectionSocketFactory> socketFactoryRegistry) {
		return post(url, headers, formData, charset, socketFactoryRegistry, 0);
	}
	/**
	 * HTTP POST请求
	 * @param url
	 * @param headers
	 * @return
	 */
	public static String post(String url, Map<String, String> headers, Map<String, String> formData, String charset, Registry<ConnectionSocketFactory> socketFactoryRegistry, int socketTime) {
		if(charset == null || charset.trim().isEmpty()) {
			charset = "UTF-8";
		}

		CloseableHttpResponse response = null;
		HttpEntity entity = null;

		PoolingHttpClientConnectionManager phccm = getPhccm(socketFactoryRegistry);
		phccm.setMaxTotal(800);// 连接池最大并发连接数
		phccm.setDefaultMaxPerRoute(400);// 单路由最大并发数

		CloseableHttpClient httpclient = null;
		if(socketTime == 0){
			httpclient = HttpClients.custom().setDefaultRequestConfig(requestConfig)
					.setConnectionManager(phccm).setRetryHandler(new DefaultHttpRequestRetryHandler()).setHttpProcessor(getProcessor()).build();
		}else{
			RequestConfig reqConfig = RequestConfig.custom().setSocketTimeout(socketTime)
					.setConnectTimeout(15000).setConnectionRequestTimeout(10000).build();
			httpclient = HttpClients.custom().setDefaultRequestConfig(reqConfig)
					.setConnectionManager(phccm).setRetryHandler(new DefaultHttpRequestRetryHandler()).setHttpProcessor(getProcessor()).build();
		}

		HttpPost httpPost = new HttpPost(url);

		// 设置HTTP头信息
		if(headers != null && !headers.isEmpty()) {
			for(Map.Entry<String, String> entry : headers.entrySet()) {
				Header header = new BasicHeader(entry.getKey(), entry.getValue());
				httpPost.addHeader(header);
			}
		} else {
			Header header = new BasicHeader("User-Agent",
					"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.134 Safari/537.36");
			httpPost.addHeader(header);
		}

		// 设置参数
		if(formData != null && !formData.isEmpty()) {
			List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
			for(Map.Entry<String, String> entry : formData.entrySet()) {
				params.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
			}

			try {
				httpPost.setEntity(new UrlEncodedFormEntity(params,charset));
			} catch(UnsupportedEncodingException e) {
				logger.warn("post请求异常",e);
				throw new CommonUtilException("post请求异常, url: " + url + "headers: " + headers + "formData: " + formData, e);
			}
		}

		try {
			response = httpclient.execute(httpPost);
			entity = response.getEntity();
			if(entity == null){
				return "";
			}
			return EntityUtils.toString(entity,charset);
		} catch(ClientProtocolException e) {
			logger.warn("post请求异常",e);
			throw new CommonUtilException("post请求异常, url: " + url + "headers: " + headers + "formData: " + formData, e);
		} catch(ParseException e) {
			logger.warn("post请求异常",e);
			throw new CommonUtilException("post请求异常, url: " + url + "headers: " + headers + "formData: " + formData, e);
		} catch (SocketTimeoutException e){
			logger.warn("post请求异常",e);
			throw new CommonUtilException("post请求异常, url: " + url + "headers: " + headers + "formData: " + formData, e);
		}catch(IOException e) {
			logger.warn("post请求异常",e);
			throw new CommonUtilException("post请求异常, url: " + url + "headers: " + headers + "formData: " + formData, e);
		}finally {
			if(entity != null) {
				try {
					EntityUtils.consume(entity);
				} catch(IOException e) {
					logger.warn("",e);
				}
			}

			if(response != null) {
				try {
					response.close();
				} catch(IOException e) {
					logger.warn("",e);
				}
			}

			httpPost.releaseConnection();
		}
	}

	public static String post(String url, Map<String, String> headers, List<Map<String,String>> formData, String charset) {
		if(charset == null || charset.trim().isEmpty()) {
			charset = "UTF-8";
		}

		CloseableHttpResponse response = null;
		HttpEntity entity = null;

		PoolingHttpClientConnectionManager phccm = getPhccm();
		phccm.setMaxTotal(800);// 连接池最大并发连接数
		phccm.setDefaultMaxPerRoute(400);// 单路由最大并发数

		CloseableHttpClient httpclient = HttpClients.custom().setDefaultRequestConfig(requestConfig)
				.setConnectionManager(phccm).setRetryHandler(new DefaultHttpRequestRetryHandler()).setHttpProcessor(getProcessor()).build();

		HttpPost httpPost = new HttpPost(url);

		// 设置HTTP头信息
		if(headers != null && !headers.isEmpty()) {
			for(Map.Entry<String, String> entry : headers.entrySet()) {
				Header header = new BasicHeader(entry.getKey(), entry.getValue());
				httpPost.addHeader(header);
			}
		} else {
			Header header = new BasicHeader("User-Agent",
					"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.134 Safari/537.36");
			httpPost.addHeader(header);
		}

		// 设置参数
		if(formData != null && !formData.isEmpty()) {
			List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
			for (Map<String, String> datum : formData) {
				for (Map.Entry<String, String> entry : datum.entrySet()) {
					params.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
				}
			}

			try {
				httpPost.setEntity(new UrlEncodedFormEntity(params, charset));
			} catch (UnsupportedEncodingException e) {
				logger.warn("post请求异常", e);
				throw new CommonUtilException("post请求异常, url: " + url + "headers: " + headers + "formData: " + formData, e);
			}
		}

		try {
			response = httpclient.execute(httpPost);
			entity = response.getEntity();
			if(entity == null){
				return "";
			}
			return EntityUtils.toString(entity,charset);
		} catch(ClientProtocolException e) {
			logger.warn("post请求异常",e);
			throw new CommonUtilException("post请求异常, url: " + url + "headers: " + headers + "formData: " + formData, e);
		} catch(ParseException e) {
			logger.warn("post请求异常",e);
			throw new CommonUtilException("post请求异常, url: " + url + "headers: " + headers + "formData: " + formData, e);
		} catch (SocketTimeoutException e){
			logger.warn("post请求异常",e);
			throw new CommonUtilException("post请求异常, url: " + url + "headers: " + headers + "formData: " + formData, e);
		}catch(IOException e) {
			logger.warn("post请求异常",e);
			throw new CommonUtilException("post请求异常, url: " + url + "headers: " + headers + "formData: " + formData, e);
		}finally {
			if(entity != null) {
				try {
					EntityUtils.consume(entity);
				} catch(IOException e) {
					logger.warn("",e);
				}
			}

			if(response != null) {
				try {
					response.close();
				} catch(IOException e) {
					logger.warn("",e);
				}
			}

			httpPost.releaseConnection();
		}
	}

	public static String post(String url, Map<String, String> headers, String reqBodyStr, String charset, String contentType){
		return post(url, headers, reqBodyStr, charset, contentType, 0);
	}

	/**
	 * HTTP POST请求
	 * @param url
	 * @param headers
	 * @param reqBodyStr
	 * @param charset
	 * @param contentType
	 * @param socketTimeout
	 * @return
	 */
	public static String post(String url, Map<String, String> headers, String reqBodyStr, String charset,
							  String contentType, int socketTimeout) {
		return post(url, headers, reqBodyStr, charset, contentType, socketTimeout, null);
	}

	/**
	 *
	 * @param url
	 * @param headers
	 * @param reqBodyStr
	 * @param charset
	 * @param socketFactoryRegistry
	 * @return
	 */
	public static String post(String url, Map<String, String> headers, String reqBodyStr, String charset, Registry<ConnectionSocketFactory> socketFactoryRegistry) {
		return post(url, headers, reqBodyStr, charset, "application/json", 0, socketFactoryRegistry);
	}

	/**
	 * HTTP POST请求
	 * @param url
	 * @param headers
	 * @param reqBodyStr
	 * @param charset
	 * @param contentType
	 * @param socketTimeout
	 * @return
	 */
	public static String post(String url, Map<String, String> headers, String reqBodyStr, String charset,
							  String contentType, int socketTimeout,
							  Registry<ConnectionSocketFactory> socketFactoryRegistry) {

		return post(url, headers, reqBodyStr, charset, contentType, socketTimeout, 10000, socketFactoryRegistry);
	}

	/**
	 * HTTP POST请求
	 * @param url
	 * @param headers
	 * @param reqBodyStr
	 * @param charset
	 * @param contentType
	 * @param socketTimeout
	 * @return
	 */
	public static String post(String url, Map<String, String> headers, String reqBodyStr, String charset,
							  String contentType, int socketTimeout, int connectTimeout,
							  Registry<ConnectionSocketFactory> socketFactoryRegistry) {
		if(charset == null || charset.trim().isEmpty()) {
			charset = "UTF-8";
		}

		CloseableHttpResponse response = null;
		HttpEntity entity = null;

		PoolingHttpClientConnectionManager phccm = getPhccm(socketFactoryRegistry);
		phccm.setMaxTotal(800);// 连接池最大并发连接数
		phccm.setDefaultMaxPerRoute(400);// 单路由最大并发数

		CloseableHttpClient httpclient = null;
		if(socketTimeout == 0 && connectTimeout == 0){
			httpclient = HttpClients.custom().setDefaultRequestConfig(requestConfig)
					.setConnectionManager(phccm).setRetryHandler(new DefaultHttpRequestRetryHandler()).setHttpProcessor(getProcessor()).build();
		}else{
			RequestConfig reqConfig = RequestConfig.custom().setSocketTimeout(socketTimeout == 0 ? 30000 : socketTimeout)
					.setConnectTimeout(connectTimeout == 0 ? 15000 : connectTimeout).setConnectionRequestTimeout(10000).build();
			httpclient = HttpClients.custom().setDefaultRequestConfig(reqConfig)
					.setConnectionManager(phccm).setRetryHandler(new DefaultHttpRequestRetryHandler()).setHttpProcessor(getProcessor()).build();
		}

		HttpPost httpPost = new HttpPost(url);

		// 设置HTTP头信息
		if(headers != null && !headers.isEmpty()) {
			for(Map.Entry<String, String> entry : headers.entrySet()) {
				Header header = new BasicHeader(entry.getKey(), entry.getValue());
				httpPost.addHeader(header);
			}
		} else {
			Header header = new BasicHeader("User-Agent",
					"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.134 Safari/537.36");
			httpPost.addHeader(header);
		}

		StringEntity reqBodyParams = new StringEntity(reqBodyStr, charset);
		reqBodyParams.setContentType(contentType);
		httpPost.setEntity(reqBodyParams);

		try {
			response = httpclient.execute(httpPost);
			entity = response.getEntity();
			if(entity == null){
				return "";
			}
			return EntityUtils.toString(entity,charset);
		} catch(ClientProtocolException e) {
			logger.warn("post请求异常",e);
			throw new CommonUtilException("post请求异常, url: " + url + "headers: " + headers + "request body: " + reqBodyStr, e);
		} catch(ParseException e) {
			logger.warn("post请求异常",e);
			throw new CommonUtilException("post请求异常, url: " + url + "headers: " + headers + "request body: " + reqBodyStr, e);
		} catch(IOException e) {
			logger.warn("post请求异常",e);
			throw new CommonUtilException("post请求异常, url: " + url + "headers: " + headers + "request body: " + reqBodyStr, e);
		} finally {
			if(entity != null) {
				try {
					EntityUtils.consume(entity);
				} catch(IOException e) {
					logger.warn("",e);
				}
			}

			if(response != null) {
				try {
					response.close();
				} catch(IOException e) {
					logger.warn("",e);
				}
			}

			httpPost.releaseConnection();
		}
	}


	/**
	 * HTTP POST请求
	 * @param url
	 * @return
	 */
	public static String post(String url, Map<String, String> headers, String reqBodyStr, String charset) {
		return post(url, headers, reqBodyStr, charset, "application/json", 0);
	}

	/**
	 * HTTP POST请求， 指定超时时间
	 * @param url
	 * @param headers
	 * @param reqBodyStr
	 * @param charset
	 * @param socketTimeout
	 * @return
	 */
	public static String post(String url, Map<String, String> headers, String reqBodyStr, String charset, int socketTimeout) {
		return post(url, headers, reqBodyStr, charset, "application/json", socketTimeout);
	}

	/**
	 * HTTP POST请求, 获取重定向数据
	 * @param url
	 * @param headers
	 * @param reqBodyStr
	 * @param charset
	 * @param contentType
	 * @param socketTimeout
	 * @param socketFactoryRegistry
	 * @return
	 */
	public static String postForRedirect(String url, Map<String, String> headers, String reqBodyStr, String charset,
										 String contentType, int socketTimeout,
										 Registry<ConnectionSocketFactory> socketFactoryRegistry) {
		if (charset == null || charset.trim().isEmpty()) {
			charset = "UTF-8";
		}

		CloseableHttpResponse response = null;
		HttpEntity entity = null;

		PoolingHttpClientConnectionManager phccm = getPhccm(socketFactoryRegistry);
		phccm.setMaxTotal(800);// 连接池最大并发连接数
		phccm.setDefaultMaxPerRoute(400);// 单路由最大并发数

		CloseableHttpClient httpclient = null;
		if (socketTimeout == 0) {
			httpclient = HttpClients.custom().setDefaultRequestConfig(requestConfig)
					.setConnectionManager(phccm).setRetryHandler(new DefaultHttpRequestRetryHandler()).setHttpProcessor(getProcessor()).build();
		} else {
			RequestConfig reqConfig = RequestConfig.custom().setSocketTimeout(socketTimeout)
					.setConnectTimeout(10000).setConnectionRequestTimeout(10000).build();
			httpclient = HttpClients.custom().setDefaultRequestConfig(reqConfig)
					.setConnectionManager(phccm).setRetryHandler(new DefaultHttpRequestRetryHandler()).setHttpProcessor(getProcessor()).build();
		}

		HttpPost httpPost = new HttpPost(url);

		// 设置HTTP头信息
		if (headers != null && !headers.isEmpty()) {
			for (Map.Entry<String, String> entry : headers.entrySet()) {
				Header header = new BasicHeader(entry.getKey(), entry.getValue());
				httpPost.addHeader(header);
			}
		} else {
			Header header = new BasicHeader("User-Agent",
					"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.134 Safari/537.36");
			httpPost.addHeader(header);
		}

		StringEntity reqBodyParams = new StringEntity(reqBodyStr, charset);
		reqBodyParams.setContentType(contentType);
		httpPost.setEntity(reqBodyParams);

		try {
			response = httpclient.execute(httpPost);
			if (response.getStatusLine() != null) {

				int statusCode = response.getStatusLine().getStatusCode();

				if (statusCode == 302) {
					Header header = response.getFirstHeader("location"); // 跳转的目标地址是在 HTTP-HEAD 中的
					String redirectUrl = header.getValue();// 这就是跳转后的地址，再向这个地址发出新申请，以便得到跳转后的信息是啥。

					httpPost = new HttpPost(redirectUrl);
					httpPost.setHeader("Content-Type", "application/json;charset=UTF-8");

					reqBodyParams = new StringEntity(reqBodyStr, charset);
					reqBodyParams.setContentType("application/json");

					httpPost.setEntity(reqBodyParams);

					response = httpclient.execute(httpPost);
				}
			}

			entity = response.getEntity();
			if (entity == null) {
				return "";
			}
			return EntityUtils.toString(entity, charset);
		} catch (ClientProtocolException e) {
			logger.warn("post请求异常", e);
			throw new CommonUtilException("post请求异常, url: " + url + "headers: " + headers + "request body: " + reqBodyStr, e);
		} catch (ParseException e) {
			logger.warn("post请求异常", e);
			throw new CommonUtilException("post请求异常, url: " + url + "headers: " + headers + "request body: " + reqBodyStr, e);
		} catch (IOException e) {
			logger.warn("post请求异常", e);
			throw new CommonUtilException("post请求异常, url: " + url + "headers: " + headers + "request body: " + reqBodyStr, e);
		} finally {
			if (entity != null) {
				try {
					EntityUtils.consume(entity);
				} catch (IOException e) {
					logger.warn("", e);
				}
			}

			if (response != null) {
				try {
					response.close();
				} catch (IOException e) {
					logger.warn("", e);
				}
			}

			httpPost.releaseConnection();
		}
	}


	/**
	 * HTTP PUT请求
	 * @param url
	 * @param headers
	 * @param charset
	 * @return
	 */
	public static String put(String url, Map<String, String> headers, String reqBodyStr, String charset,String contentType) {
		if(charset == null || charset.trim().isEmpty()) {
			charset = "UTF-8";
		}

		CloseableHttpResponse response = null;
		HttpEntity entity = null;

		PoolingHttpClientConnectionManager phccm = getPhccm();
		phccm.setMaxTotal(800);// 连接池最大并发连接数
		phccm.setDefaultMaxPerRoute(400);// 单路由最大并发数

		CloseableHttpClient httpclient = HttpClients.custom().setDefaultRequestConfig(requestConfig)
				.setConnectionManager(phccm).setRetryHandler(new DefaultHttpRequestRetryHandler()).setHttpProcessor(getProcessor()).build();

		HttpPut httpPut = new HttpPut(url);
//		HttpPost httpPost = new HttpPost(url);

		// 设置HTTP头信息
		if(headers != null && !headers.isEmpty()) {
			for(Map.Entry<String, String> entry : headers.entrySet()) {
				Header header = new BasicHeader(entry.getKey(), entry.getValue());
				httpPut.addHeader(header);
			}
		} else {
			Header header = new BasicHeader("User-Agent",
					"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.134 Safari/537.36");
			httpPut.addHeader(header);
		}

		StringEntity reqBodyParams = new StringEntity(reqBodyStr, charset);
		reqBodyParams.setContentType(contentType);
		httpPut.setEntity(reqBodyParams);

		try {
			response = httpclient.execute(httpPut);
			entity = response.getEntity();
			if(entity == null){
				return "";
			}
			return EntityUtils.toString(entity, charset);
		} catch(ClientProtocolException e) {
			logger.warn("post请求异常",e);
			throw new CommonUtilException("put请求异常, url: " + url + "headers: " + headers, e);
		} catch(ParseException e) {
			logger.warn("post请求异常",e);
			throw new CommonUtilException("put请求异常, url: " + url + "headers: " + headers, e);
		} catch(IOException e) {
			logger.warn("post请求异常",e);
			throw new CommonUtilException("put请求异常, url: " + url + "headers: " + headers, e);
		} finally {
			if(entity != null) {
				try {
					EntityUtils.consume(entity);
				} catch(IOException e) {
					logger.warn("",e);
				}
			}

			if(response != null) {
				try {
					response.close();
				} catch(IOException e) {
					logger.warn("",e);
				}
			}

			httpPut.releaseConnection();
		}
	}

	/**
	 * HTTP PUT请求
	 * @param url
	 * @param headers
	 * @param charset
	 * @return
	 */
	public static String put(String url, Map<String, String> headers, String reqBodyStr, String charset) {
		if(charset == null || charset.trim().isEmpty()) {
			charset = "UTF-8";
		}

		CloseableHttpResponse response = null;
		HttpEntity entity = null;

		PoolingHttpClientConnectionManager phccm = getPhccm();
		phccm.setMaxTotal(800);// 连接池最大并发连接数
		phccm.setDefaultMaxPerRoute(400);// 单路由最大并发数

		CloseableHttpClient httpclient = HttpClients.custom().setDefaultRequestConfig(requestConfig)
				.setConnectionManager(phccm).setRetryHandler(new DefaultHttpRequestRetryHandler()).setHttpProcessor(getProcessor()).build();

		HttpPut httpPut = new HttpPut(url);
//		HttpPost httpPost = new HttpPost(url);

		// 设置HTTP头信息
		if(headers != null && !headers.isEmpty()) {
			for(Map.Entry<String, String> entry : headers.entrySet()) {
				Header header = new BasicHeader(entry.getKey(), entry.getValue());
				httpPut.addHeader(header);
			}
		} else {
			Header header = new BasicHeader("User-Agent",
					"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.134 Safari/537.36");
			httpPut.addHeader(header);
		}

		StringEntity reqBodyParams = new StringEntity(reqBodyStr, charset);
		reqBodyParams.setContentType(charset);
		httpPut.setEntity(reqBodyParams);

		try {
			response = httpclient.execute(httpPut);
			entity = response.getEntity();
			if(entity == null){
				return "";
			}
			return EntityUtils.toString(entity, charset);
		} catch(ClientProtocolException e) {
			logger.warn("post请求异常",e);
			throw new CommonUtilException("put请求异常, url: " + url + "headers: " + headers, e);
		} catch(ParseException e) {
			logger.warn("post请求异常",e);
			throw new CommonUtilException("put请求异常, url: " + url + "headers: " + headers, e);
		} catch(IOException e) {
			logger.warn("post请求异常",e);
			throw new CommonUtilException("put请求异常, url: " + url + "headers: " + headers, e);
		} finally {
			if(entity != null) {
				try {
					EntityUtils.consume(entity);
				} catch(IOException e) {
					logger.warn("",e);
				}
			}

			if(response != null) {
				try {
					response.close();
				} catch(IOException e) {
					logger.warn("",e);
				}
			}

			httpPut.releaseConnection();
		}
	}

	public static String put(String url, Map<String, String> headers, String charset) {
		if(charset == null || charset.trim().isEmpty()) {
			charset = "UTF-8";
		}

		CloseableHttpResponse response = null;
		HttpEntity entity = null;

		PoolingHttpClientConnectionManager phccm = getPhccm();
		phccm.setMaxTotal(800);// 连接池最大并发连接数
		phccm.setDefaultMaxPerRoute(400);// 单路由最大并发数

		CloseableHttpClient httpclient = HttpClients.custom().setDefaultRequestConfig(requestConfig)
				.setConnectionManager(phccm).setRetryHandler(new DefaultHttpRequestRetryHandler()).setHttpProcessor(getProcessor()).build();

		HttpPut httpPut = new HttpPut(url);
//		HttpPost httpPost = new HttpPost(url);

		// 设置HTTP头信息
		if(headers != null && !headers.isEmpty()) {
			for(Map.Entry<String, String> entry : headers.entrySet()) {
				Header header = new BasicHeader(entry.getKey(), entry.getValue());
				httpPut.addHeader(header);
			}
		} else {
			Header header = new BasicHeader("User-Agent",
					"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.134 Safari/537.36");
			httpPut.addHeader(header);
		}

//		StringEntity reqBodyParams = new StringEntity(reqBodyStr, charset);
//		reqBodyParams.setContentType(contentType);
//		httpPut.setEntity(reqBodyParams);

		try {
			response = httpclient.execute(httpPut);
			entity = response.getEntity();
			if(entity == null){
				return "";
			}
			return EntityUtils.toString(entity, charset);
		} catch(ClientProtocolException e) {
			logger.warn("post请求异常",e);
			throw new CommonUtilException("put请求异常, url: " + url + "headers: " + headers, e);
		} catch(ParseException e) {
			logger.warn("post请求异常",e);
			throw new CommonUtilException("put请求异常, url: " + url + "headers: " + headers, e);
		} catch(IOException e) {
			logger.warn("post请求异常",e);
			throw new CommonUtilException("put请求异常, url: " + url + "headers: " + headers, e);
		} finally {
			if(entity != null) {
				try {
					EntityUtils.consume(entity);
				} catch(IOException e) {
					logger.warn("",e);
				}
			}

			if(response != null) {
				try {
					response.close();
				} catch(IOException e) {
					logger.warn("",e);
				}
			}

			httpPut.releaseConnection();
		}
	}


	/**
	 * HTTP patch请求
	 * @param url
	 * @param headers
	 * @param charset
	 * @return
	 */
	public static String patch(String url, Map<String, String> headers, String charset) {
		if(charset == null || charset.trim().isEmpty()) {
			charset = "UTF-8";
		}

		CloseableHttpResponse response = null;
		HttpEntity entity = null;

		PoolingHttpClientConnectionManager phccm = getPhccm();
		phccm.setMaxTotal(800);// 连接池最大并发连接数
		phccm.setDefaultMaxPerRoute(400);// 单路由最大并发数

		CloseableHttpClient httpclient = HttpClients.custom().setDefaultRequestConfig(requestConfig)
				.setConnectionManager(phccm).setRetryHandler(new DefaultHttpRequestRetryHandler()).setHttpProcessor(getProcessor()).build();

		HttpPatch httpPatch = new HttpPatch(url);
//		HttpPost httpPost = new HttpPost(url);

		// 设置HTTP头信息
		if(headers != null && !headers.isEmpty()) {
			for(Map.Entry<String, String> entry : headers.entrySet()) {
				Header header = new BasicHeader(entry.getKey(), entry.getValue());
				httpPatch.addHeader(header);
			}
		} else {
			Header header = new BasicHeader("User-Agent",
					"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.134 Safari/537.36");
			httpPatch.addHeader(header);
		}

//		StringEntity reqBodyParams = new StringEntity(reqBodyStr, charset);
//		reqBodyParams.setContentType(contentType);
//		httpPut.setEntity(reqBodyParams);

		try {
			response = httpclient.execute(httpPatch);
			entity = response.getEntity();
			if(entity == null){
				return "";
			}
			return EntityUtils.toString(entity, charset);
		} catch(ClientProtocolException e) {
			logger.warn("post请求异常",e);
			throw new CommonUtilException("put请求异常, url: " + url + "headers: " + headers, e);
		} catch(ParseException e) {
			logger.warn("post请求异常",e);
			throw new CommonUtilException("put请求异常, url: " + url + "headers: " + headers, e);
		} catch(IOException e) {
			logger.warn("post请求异常",e);
			throw new CommonUtilException("put请求异常, url: " + url + "headers: " + headers, e);
		} finally {
			if(entity != null) {
				try {
					EntityUtils.consume(entity);
				} catch(IOException e) {
					logger.warn("",e);
				}
			}

			if(response != null) {
				try {
					response.close();
				} catch(IOException e) {
					logger.warn("",e);
				}
			}

			httpPatch.releaseConnection();
		}
	}

	/**
	 * HTTP DELETE请求
	 * @param url
	 * @param headers
	 * @param charset
	 * @return
	 */
	public static String delete(String url, Map<String, String> headers, String charset) {
		if(charset == null || charset.trim().isEmpty()) {
			charset = "UTF-8";
		}

		CloseableHttpResponse response = null;
		HttpEntity entity = null;

		PoolingHttpClientConnectionManager phccm = getPhccm();
		phccm.setMaxTotal(800);// 连接池最大并发连接数
		phccm.setDefaultMaxPerRoute(400);// 单路由最大并发数

		CloseableHttpClient httpclient = HttpClients.custom().setDefaultRequestConfig(requestConfig)
				.setConnectionManager(phccm).setRetryHandler(new DefaultHttpRequestRetryHandler()).setHttpProcessor(getProcessor()).build();

		HttpDelete httpDelete = new HttpDelete(url);

		// 设置HTTP头信息
		if(headers != null && !headers.isEmpty()) {
			for(Map.Entry<String, String> entry : headers.entrySet()) {
				Header header = new BasicHeader(entry.getKey(), entry.getValue());
				httpDelete.addHeader(header);
			}
		} else {
			Header header = new BasicHeader("User-Agent",
					"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.134 Safari/537.36");
			httpDelete.addHeader(header);
		}

		try {
			response = httpclient.execute(httpDelete);
			entity = response.getEntity();
			if(entity == null){
				return "";
			}
			return EntityUtils.toString(entity, charset);
		} catch(ClientProtocolException e) {
			logger.warn("post请求异常",e);
			throw new CommonUtilException("delete请求异常, url: " + url + "headers: " + headers, e);
		} catch(ParseException e) {
			logger.warn("post请求异常",e);
			throw new CommonUtilException("delete请求异常, url: " + url + "headers: " + headers, e);
		} catch(IOException e) {
			logger.warn("post请求异常",e);
			throw new CommonUtilException("delete请求异常, url: " + url + "headers: " + headers, e);
		} finally {
			if(entity != null) {
				try {
					EntityUtils.consume(entity);
				} catch(IOException e) {
					logger.warn("",e);
				}
			}

			if(response != null) {
				try {
					response.close();
				} catch(IOException e) {
					logger.warn("",e);
				}
			}

			httpDelete.releaseConnection();
		}
	}
	public static HttpProcessor getProcessor() {
		final BasicHttpProcessor httpproc = new BasicHttpProcessor();

		HttpResponseInterceptor contentEncodingFixerInterceptor = new ResponseContentEncoding()  {
			@Override
			public void process(HttpResponse response, HttpContext context) throws HttpException, IOException {
				try {
					super.process(response, context);
				} catch (HttpException e) {
					if ("Unsupported Content-Coding: none".equalsIgnoreCase(e.getMessage())) {
					} else {
						throw e;
					}
				}
			}
		};

		httpproc.addInterceptor(new RequestDefaultHeaders());
		// Required protocol interceptors
		httpproc.addInterceptor(new RequestContent());
		httpproc.addInterceptor(new RequestTargetHost());
		// Recommended protocol interceptors
		httpproc.addInterceptor(new RequestClientConnControl());
		httpproc.addInterceptor(new RequestUserAgent());
		httpproc.addInterceptor(new RequestExpectContinue());
		// HTTP state management interceptors
		httpproc.addInterceptor(new RequestAddCookies());
		httpproc.addInterceptor(new ResponseProcessCookies());
		// HTTP authentication interceptors
		httpproc.addInterceptor(new RequestAuthCache());
		httpproc.addInterceptor(new RequestTargetAuthentication());
		httpproc.addInterceptor(new RequestProxyAuthentication());

		httpproc.addRequestInterceptor(new RequestAcceptEncoding());
		httpproc.addInterceptor(contentEncodingFixerInterceptor);

		// Get mutable HTTP processor
		// and create an immutable copy of it
		final int reqc = httpproc.getRequestInterceptorCount();
		final HttpRequestInterceptor[] reqinterceptors = new HttpRequestInterceptor[reqc];
		for (int i = 0; i < reqc; i++) {
			reqinterceptors[i] = httpproc.getRequestInterceptor(i);
		}
		final int resc = httpproc.getResponseInterceptorCount();
		final HttpResponseInterceptor[] resinterceptors = new HttpResponseInterceptor[resc];
		for (int i = 0; i < resc; i++) {
			resinterceptors[i] = httpproc.getResponseInterceptor(i);
		}
		HttpProcessor protocolProcessor = new ImmutableHttpProcessor(reqinterceptors, resinterceptors);

		return protocolProcessor;
	}

	/**
	 * URLEncode参数并拼接
	 */
	public static String concatParamsWithURLEncode(Map<String, String> map) throws UnsupportedEncodingException {
		return  concatParamsWithURLEncode(map, "utf-8");
	}

	/**
	 * URLEncode参数并拼接
	 */
	public static String concatParamsWithURLEncode(Map<String, String> map, String charset) throws UnsupportedEncodingException {
		if (map == null || map.size() <= 0) {
			return "";
		}

		StringBuilder sb = new StringBuilder();
		Set<Map.Entry<String, String>> entrySet = map.entrySet();
		for(Map.Entry<String, String> entry : entrySet){
			if (entry.getValue() != null) {
				if(sb.length() > 0){
					sb.append("&");
				}
				sb.append(entry.getKey()).append("=").append(URLEncoder.encode(entry.getValue(), charset));
			}
		}

		return  sb.toString();
	}
	public static void main(String[] args) {
//		HttpUtils.downloadInFile("http://api.test.lohoo.com/xml/v2.0/hotel/hotellist.xml", "E:/file2/elong/testxml.txt");
//		HttpUtils.downloadLittleFile("http://api.test.lohoo.com/xml/v2.0/hotel/hotellist.xml", "E:/file2/elong/testxml_ww.txt");
//		String response = post("http://www.baidu222222.com", "{\"businessId\":\"23057997\",\"financeCategory\":\"TicketOutSuccess\"}");
//		System.out.println(response);
		String response = postRetryWhenConnectTimeout("http://www.baidu.com", "{}", "application/json;charset=UTF-8", 30000, 1);
	}
	
}
